package com.carleasoft.mps.adu.business.login.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.carleasoft.mps.adu.business.login.bean.BowOutVo;
import com.carleasoft.mps.adu.business.login.bean.LoginResultVo;
import com.carleasoft.mps.adu.business.login.bean.LoginUserPermVo;
import com.carleasoft.mps.adu.business.login.bean.ToLoginVo;
import com.carleasoft.mps.adu.business.login.service.LoginService;
import com.carleasoft.mps.adu.business.menu.service.AuthorityMenuService;
import com.carleasoft.mps.adu.business.role.bean.vo.AuthorityRoleVo;
import com.carleasoft.mps.adu.business.role.bean.vo.PermVo;
import com.carleasoft.mps.adu.business.role.service.GrantPermsService;
import com.carleasoft.mps.adu.business.user.bean.entity.AuthorityUserEntity;
import com.carleasoft.mps.adu.business.user.bean.entity.AuthorityUserPositionEntity;
import com.carleasoft.mps.adu.business.user.dao.AuthorityUserDao;
import com.carleasoft.mps.adu.business.user.dao.AuthorityUserDeptDao;
import com.carleasoft.mps.adu.business.user.dao.AuthorityUserPositionDao;
import com.carleasoft.mps.adu.common.constants.BusinessErrorEnum;
import com.carleasoft.mps.core.exceptions.BusinessException;
import com.carleasoft.mps.core.perm.AllCache;
import com.carleasoft.mps.core.user.*;
import com.carleasoft.mps.core.perm.DataPermCache;
import com.carleasoft.mps.core.perm.PermissionMenuCache;
import com.carleasoft.mps.core.utils.ConvertUtils;
import com.carleasoft.mps.core.utils.ExceptionUtil;
import com.carleasoft.mps.data.redis.JedisService;
import com.carleasoft.mps.data.redis.base.CacheKeyEnum;
import com.carleasoft.mps.security.permission.access.security.JwtProperties;
import com.carleasoft.mps.security.permission.access.security.JwtUtil;
import com.google.common.base.Joiner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 登录 Service
 *
 * @author ztm
 * @since 2020/4/28
 */
@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    private AuthorityUserDao authorityUserDao;
    @Autowired
    private JedisService jedisService;
    @Autowired
    private JwtProperties jwtProperties;
    @Autowired
    private AuthorityUserDeptDao authorityUserDeptDao;
    @Autowired
    AuthorityUserPositionDao authorityUserPositionDao;
    @Autowired
    private GrantPermsService permsService;
    @Autowired
    private AuthorityMenuService authorityMenuService;


    /**
     * 登录
     *
     * @return String
     * @paramt toLoginVo
     */
    @Override
    public LoginResultVo toLogin(ToLoginVo toLoginVo) {
        LoginResultVo loginResultVo = new LoginResultVo();
        // 验证用户名密码是否错误
        AuthorityUserEntity userEntity = authorityUserDao.selectOne(Wrappers.<AuthorityUserEntity>lambdaQuery()
                .eq(AuthorityUserEntity::getUserPassword, toLoginVo.getUserPassword())
                .eq(AuthorityUserEntity::getUserAccount, toLoginVo.getUserAccount()));

        if (userEntity == null || StringUtils.isEmpty(userEntity.getUserCode())) {
            throw ExceptionUtil.create(BusinessErrorEnum.USER_PASSWORD_ERROR);
        }
        if (userEntity.getUserStatus().equals(Constants.DISABLE)) {
            throw ExceptionUtil.create(BusinessErrorEnum.USER_DISABLE);
        }

        String currentTimeMillis = String.valueOf(System.currentTimeMillis());

        String token = JwtUtil.sign(userEntity.getUserAccount(), currentTimeMillis);
        if (token == null) {
            throw ExceptionUtil.create(BusinessErrorEnum.USER_PASSWORD_SIGN);
        }
        //更新RefreshToken缓存的时间戳

        jedisService.addString(CacheKeyEnum.PREFIX_SHIRO_REFRESH_TOKEN, userEntity.getUserAccount(), currentTimeMillis, jwtProperties.getTokenExpireTime() * 60);

        AllCache allCache = this.buildUser(userEntity.getUserAccount());

        loginResultVo.setUserCacheData(allCache.getUserCacheData());

        jedisService.addObject(CacheKeyEnum.PREFIX_UESRCACHE, userEntity.getUserAccount(), allCache.getUserCacheData());
        jedisService.addObject(CacheKeyEnum.PREFIX_PERMS_CACHE_DATA, userEntity.getUserAccount(), allCache.getDataPermCache());
        jedisService.addObject(CacheKeyEnum.PREFIX_PERMS_CACHE_MENU, userEntity.getUserAccount(), allCache.getPermissionMenuCache());

        loginResultVo.setToken(token);
        loginResultVo.setUserCode(userEntity.getUserCode());
        loginResultVo.setUserCat(userEntity.getUserCat());

        if (toLoginVo.getLoginType().equals(Constants.WEB)) {
            loginResultVo.setWebResources(allCache.getPermissionMenuCache().getWebMenuCode());
        }
        if (toLoginVo.getLoginType().equals(Constants.APP)) {
            loginResultVo.setAppResources(allCache.getPermissionMenuCache().getAppMenuCode());
        }
        return loginResultVo;
    }

    @Override
    public LoginUserPermVo getLoginUserMenuPerm(String userAccount, Integer loginType) {
        if (StringUtils.isEmpty(userAccount)) throw ExceptionUtil.create(BusinessErrorEnum.ORG_DELETE_ERROR);
        LoginUserPermVo loginUserPermVo = new LoginUserPermVo();
        PermissionMenuCache permissionMenuCache = (PermissionMenuCache) jedisService.getObject(CacheKeyEnum.PREFIX_PERMS_CACHE_MENU, userAccount);
        if (permissionMenuCache == null) {
            AllCache allCache = this.buildUser(userAccount);
            jedisService.addObject(CacheKeyEnum.PREFIX_UESRCACHE, userAccount, allCache.getUserCacheData());
            jedisService.addObject(CacheKeyEnum.PREFIX_PERMS_CACHE_DATA, userAccount, allCache.getDataPermCache());
            jedisService.addObject(CacheKeyEnum.PREFIX_PERMS_CACHE_MENU, userAccount, allCache.getPermissionMenuCache());
            permissionMenuCache = allCache.getPermissionMenuCache();
        }
        if (permissionMenuCache != null) {
            if (loginType.equals(Constants.WEB)) {
                PermVo permVo = authorityMenuService.getMenuAndButton(permissionMenuCache.getWebMenuCode());
                loginUserPermVo.setWebResources(permVo);
            }
            if (loginType.equals(Constants.APP)) {
                PermVo permVo = authorityMenuService.getMenuAndButton(permissionMenuCache.getAppMenuCode());
                loginUserPermVo.setWebResources(permVo);
            }
        }
        if (loginUserPermVo==null || (loginUserPermVo.getAppResources()==null && loginUserPermVo.getWebResources()==null && loginUserPermVo.getClientResources()==null))
        {
            throw new BusinessException(BusinessErrorEnum.COUNT_NO_JURISDICTION);
        }
        return loginUserPermVo;
    }

    /**
     * 登录
     *
     * @return String
     * @paramt userAccount
     */
    @Override
    public AllCache buildUser(String userAccount) {
        //缓存用户信息
        AllCache allCache = new AllCache();
        UserCacheData userCacheData = new UserCacheData();
        AuthorityUserEntity userEntity = authorityUserDao.selectOne(new QueryWrapper<AuthorityUserEntity>()
                .eq("USER_ACCOUNT", userAccount));
        if (userEntity == null || StringUtils.isEmpty(userEntity.getUserCode())) {
            throw ExceptionUtil.create(BusinessErrorEnum.USER_PASSWORD_ERROR);
        }

        //得到用户部门，org信息,职务
        Set<String> deptCodeList = new HashSet<>();
        Set<String> orgCodelist = new HashSet<>();
        List<UserPro> userPros = new ArrayList<>();
        Map<String, List<UserDeptVo>> userDeptVos = authorityUserDeptDao.getDeptByUserCode(userEntity.getUserCode()).stream().collect(Collectors.groupingBy(UserDeptVo::getOrganizationCode));
        List<AuthorityUserPositionEntity> userPositions = authorityUserPositionDao.selectPositionByUserCode(userEntity.getUserCode());


        for (String orgCode : userDeptVos.keySet()){
            orgCodelist.add(orgCode);
            UserPro userPro = new UserPro();
            userDeptVos.get(orgCode).forEach(userDeptItem -> {
                        userPro.setOrganizationCode(userDeptItem.getOrganizationCode());
                        userPro.setOrganizationName(userDeptItem.getOrganizationName());
                        userPositions.forEach(posItem -> {
                            if (userDeptItem.getDeptCode().equals(posItem.getDeptCode())) {
                                userDeptItem.getUserPositionList().add(ConvertUtils.sourceToTarget(posItem, UserPositionVo.class));
                            }
                        });
                        deptCodeList.add(userDeptItem.getDeptCode());
                        userPro.getUserDeptVoList().add(userDeptItem);
                    }
            );
            userPros.add(userPro);
        };


        userCacheData.setUserPros(userPros);
        userCacheData.setDeptCodeJoin(Joiner.on(",").join(deptCodeList));
        userCacheData.setOrgCodeJoin(Joiner.on(",").join(orgCodelist));
        userCacheData.setUserCode(userEntity.getUserCode());
        userCacheData.setUserName(userEntity.getUserName());
        userCacheData.setUserAccount(userEntity.getUserAccount());
        userCacheData.setUserCat(userEntity.getUserCat());
        userCacheData.setUserTypeCode(userEntity.getUserTypeCode());
        userCacheData.setOrganizationCode(userPros.get(0).getOrganizationCode());
        userCacheData.setOrganizationName(userPros.get(0).getOrganizationName());
        userCacheData.setDeptCode(userPros.get(0).getUserDeptVoList().get(0).getDeptCode());
        userCacheData.setDeptName(userPros.get(0).getUserDeptVoList().get(0).getDeptName());

        ThreadUserContext.set(userCacheData);
        allCache.setUserCacheData(userCacheData);
        AuthorityRoleVo authorityRoleVo = permsService.getAllPermsByUser(true, false);

        PermissionMenuCache permissionMenuCache = new PermissionMenuCache();
        permissionMenuCache.setAppMenuCode(authorityRoleVo.getMenuPermsVo().getAppResourcesList());
        permissionMenuCache.setWebMenuCode(authorityRoleVo.getMenuPermsVo().getWebResourcesList());
        allCache.setPermissionMenuCache(permissionMenuCache);

        DataPermCache dataPermCache = new DataPermCache();
        dataPermCache.setDataType(authorityRoleVo.getDataPermsVo().getDataType());
        dataPermCache.setOrganizationCodeTypeCodes(authorityRoleVo.getDataPermsVo().getOrgTypeCodes());
        dataPermCache.setOrganizationCodes(authorityRoleVo.getDataPermsVo().getOrgCodes());
        dataPermCache.setDeptCodes(authorityRoleVo.getDataPermsVo().getOrgCodes());
        allCache.setDataPermCache(dataPermCache);
        return allCache;
    }

    /**
     * 退出
     *
     * @param bowOutVo
     * @return void
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void bowOut(BowOutVo bowOutVo) {
        //清除redis用户token缓存
        if (!StringUtils.isEmpty(bowOutVo.getUserCode())) {

            // 清token
            String account = bowOutVo.getUserCode();

            if (jedisService.exists(CacheKeyEnum.PREFIX_SHIRO_REFRESH_TOKEN, account)) {
                jedisService.deleteString(CacheKeyEnum.PREFIX_SHIRO_REFRESH_TOKEN, account);
            }
            if (jedisService.exists(CacheKeyEnum.PREFIX_UESRCACHE, account)) {
                jedisService.deleteObject(CacheKeyEnum.PREFIX_UESRCACHE, account);
            }
        }
    }
}
